﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Reflection;
using System.Linq.Expressions;
using CoolCode.Linq;

namespace CoolCode.Data.Linq
{
    public interface IRepository<T> : IQueryable<T> , IEnumerable<T>// // where T : class
    { 
        void Insert(T entity);
        void Insert(IEnumerable<T> list);

        void Update(T entity);
        void Update(T entity, T original);
        void Update(IEnumerable<T> list);

        void Delete(T entity);
        void Delete(IQueryable<T> query);
        void Delete(IEnumerable<T> list);
        void Delete(Expression<Func<T, bool>> predicate);

        IQueryable<T> Query();
        IQueryable<T> Query(Expression<Func<T, bool>> predicate);
        IQueryable<T> Where(Expression<Func<T, bool>> predicate);

        List<T> List(IQueryable<T> query, bool withNoLock);

        T Get(Expression<Func<T, bool>> predicate);


        //ISingleResult<TResult> ExecuteStoredProcedure<TResult>(object instance, MethodInfo method, params object[] parameters);

        //IMultipleResults ExecuteStoredProcedure(object instance, MethodInfo method, params object[] parameters);
    }


    public static class RepositoryExtension
    {
        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, PageParam p) // where T : class
        {
            var q = rep.Query();
            return new PaginatedList<T>(q, p);
        }

        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, Expression<Func<T, bool>> predicate, PageParam p) // where T : class
        {
            var q = rep.Query(predicate);
            return new PaginatedList<T>(q, p);
        }


        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, Func<IQueryable<T>, IQueryable<T>> handle, PageParam p) // where T : class
        {
            var q = handle(rep.Query());
            return new PaginatedList<T>(q, p);
        }

        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, Func<IEnumerable<T>, IEnumerable<T>> handle, PageParam p) // where T : class
        {
            var q = handle(rep.Query());
            return new PaginatedList<T>(q, p);
        }

        public static List<T> List<T>(this IRepository<T> rep) // where T : class
        {
            var q = rep.Query();
            return q.ToList();
        }

        public static List<T> List<T>(this IRepository<T> rep, Expression<Func<T, bool>> predicate) // where T : class
        {
            var q = rep.Query(predicate);
            return q.ToList();
        }

        public static bool Contains<T>(this IRepository<T> rep, Expression<Func<T, bool>> predicate)   // where T : class
        {
            var q = rep.Query(predicate);
            return q.Count() > 0;
        }

        public static void Update<T>(this IRepository<T> rep, Expression<Func<T, bool>> predicate, Action<T> action) // where T : class
        {
            var list = rep.List(predicate);
            foreach (T entity in list)
                action(entity);
        }

    }

    /*
    public  interface IRepository<T> // where T : class
    {
        //void Submit();

        void Insert(T entity);
        void Insert(IEnumerable<T> list);

        void Update(T entity);
        void Update(T entity, T original);
        void Update(IEnumerable<T> list);

        void Delete(T entity);
        void Delete(IEnumerable<T> list);
        void Delete(Func<T, bool> predicate);

        IQueryable<T> Query() ;
        IEnumerable<T> Query(Func<T, bool> predicate) ;
        IQueryable<T> Where(Expression<Func<T, bool>> predicate);

        T Get(Func<T, bool> predicate);

        ISingleResult<TResult> ExecuteStoredProcedure<TResult>(object instance, MethodInfo method, params object[] parameters);

        IMultipleResults ExecuteStoredProcedure(object instance, MethodInfo method, params object[] parameters);


        //List<T> List();
        //List<T> List(Func<T, bool> predicate);

        //PaginatedList<T> Paging(PageParam p) ;
        //PaginatedList<T> Paging(Func<T, bool> predicate, PageParam p)  ;
        //PaginatedList<T> Paging(Func<IEnumerable<T>, IEnumerable<T>> handle, PageParam p);
    }


    public static class RepositoryExtension
    {
        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, PageParam p) // where T : class
        {
            var q = rep.Query();
            return new PaginatedList<T>(q, p.PageIndex, p.PageSize);
        }

        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, Func<T, bool> predicate, PageParam p) // where T : class
        {
            var q = rep.Query(predicate);
            return new PaginatedList<T>(q, p.PageIndex, p.PageSize);
        }

        public static PaginatedList<T> Paging<T>(this IRepository<T> rep, Func<IEnumerable<T>, IEnumerable<T>> handle, PageParam p) // where T : class
        {
            var q = handle(rep.Query());
            return new PaginatedList<T>(q, p.PageIndex, p.PageSize);
        }

        public static List<T> List<T>(this IRepository<T> rep) // where T : class
        {
            var q = rep.Query();
            return q.ToList();
        }

        public static List<T> List<T>(this IRepository<T> rep, Func<T, bool> predicate) // where T : class
        {
            var q = rep.Query(predicate );
            return q.ToList();
        }

        public static bool Contains<T>(this IRepository<T> rep, Func<T, bool> predicate) // where T : class
        {
            var q = rep.Query(predicate);
            return q.Count()>0;
        }

        public static void Update<T>(this IRepository<T> rep, Func<T, bool> predicate, Action<T> action)  // where T : class
        {
            var list = rep.List (predicate); 
            foreach (T entity in list)
                action(entity); 
        }
    }
     */
}
